package infod

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

var (
	_ InfoAggregateRoot = &infoAggregateRoot{}
)

func initInfo(d ddd.Domain, repo InfoRepo) {
	car := &infoAggregateRoot{}
	car.Init(car, d, DomainID)
	repo.Init(repo, car, DomainID)
	//ddd.RegAggregateRoot(d, car)
	//ddd.SetRepoForARoot(car, repo)
}

// InfoAggregateRoot 信息的聚合根
type InfoAggregateRoot interface {
	ddd.AggregateRoot
	// 新增信息
	AddInfo(ctx ddd.Context, info InfoDesc) (id string, err error)
	// 获取指定信息：根据唯一标识获取信息实体
	GetInfo(ctx ddd.Context, id string) (ia *InfoAggregate, err error)
	// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
	// total 总数量
	QueryPage(ctx ddd.Context, is InfoSearch, pi common.PageInfo) (npi common.PageResult, result []InfoAggregate, err error)
	QueryNum(ctx ddd.Context, is InfoSearch) (num int, err error)
	// 根据一组信息id获取信息列表
	// 列表按信息编号的顺序返回
	FullInfos(ctx ddd.Context, infoids []string) (result []InfoAggregate, err error)
}

// InfoRepo 信息仓储
type InfoRepo interface {
	ddd.Repository
	// 新增信息
	AddInfo(ctx ddd.Context, info InfoDesc) (id string, err error)
	// 获取指定信息：根据唯一标识获取信息实体
	GetInfo(ctx ddd.Context, infoid string) (*InfoAggregate, error)
	// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
	// total 总数量
	QueryPage(ctx ddd.Context, is InfoSearch, pi common.PageInfo) (npi common.PageResult, result []InfoAggregate, err error)
	// 获取符合条件信息数量
	QueryNum(ctx ddd.Context, is InfoSearch) (num int, err error)
	// 修改信息
	UpdateDesc(ctx ddd.Context, infoid string, info InfoDesc) error
	// 修改信息，并将状态改为初始化状态
	UpdateDescToInit(ctx ddd.Context, infoid string, info InfoDesc) error
	// 修改扩展信息
	UpdateExtral(ctx ddd.Context, infoid string, info map[string]interface{}) error
	// 删除信息 标记删除
	DeleteInfo(ctx ddd.Context, infoid string) error
	// 恢复信息 恢复删除信息
	RecoverInfo(ctx ddd.Context, infoid string) error
	// 彻底删除指定信息
	DestroyInfoByID(ctx ddd.Context, infoid string) error
	// 根据一组信息id获取信息列表
	// 列表按信息编号的顺序返回
	FullInfos(ctx ddd.Context, infoids []string) (result []InfoAggregate, err error)
	// 提交审核
	CommitCheck(ctx ddd.Context, infoid string) error
	// 审核通过
	CheckOK(ctx ddd.Context, infoid, content string) error
	// 审核不通过
	CheckNo(ctx ddd.Context, infoid, content string) error
	// 发布
	Publish(ctx ddd.Context, infoid string) error
	// 取消发布
	Unpublish(ctx ddd.Context, infoid string) error
	// 禁止发布
	ProhibitPublish(ctx ddd.Context, infoid string) error
	// 取消禁止发布
	CancelProhibitPublish(ctx ddd.Context, infoid string) error
}

// InfoSearch 查询条件
type InfoSearch struct {
	// UID OrgID 如果都为空 :
	// 	  Range 0 查询所有信息包含 所有者和所属组织的信息
	// 	  Range 1 查询除所属组织所属用户以外的信息
	// UID OrgID 任何一个不为空：
	// 	  Range 参数失效
	Range     int                    `json:"mode,omitempty"`
	UID       string                 `json:"owner,omitempty"`     // 所有者用户编号
	OrgID     string                 `json:"org,omitempty"`       // 组织编号
	ColumnID  string                 `json:"column,omitempty"`    // 栏目编号
	Key       string                 `json:"key,omitempty"`       // 关键字
	Status    []IStatus              `json:"status,omitempty"`    // -2为全部 0 初始化，1 等待审核，2审核通过，3发布成功 4，取消发布，-1 删除
	Tags      []string               `json:"tags,omitempty"`      // 匹配标签
	Creator   string                 `json:"creator,omitempty"`   //查询创建人
	Publisher string                 `json:"publisher,omitempty"` // 发布人
	Extral    map[string]interface{} `json:"extral,omitempty"`    // 扩展属性查询条件
	PubTime   *common.SchTime        `json:"pub_time,omitempty"`  // 发布时间范围查询
	CreTime   *common.SchTime        `json:"cre_time,omitempty"`  // 创建时间范围查询
}

// InfoDesc 信息描述实例
type InfoDesc struct {
	Owner    string                 `json:"owner"`     // 所有者
	Org      string                 `json:"org"`       // 所属组织
	ColumnID string                 `json:"column_id"` // 所属栏目
	Kind     int                    `json:"kind"`      // 类型 1.文章，2短文，3投票，活动，调查问卷
	Title    string                 `json:"title"`     // 标题
	SubTitle string                 `json:"sub_title"` // 副标题标题
	ListMode int                    `json:"list_mode"` // 列表展示时的默认模式
	Icon     []string               `json:"icon"`      // 图标
	Banner   string                 `json:"banner"`    // 旗帜
	From     string                 `json:"from"`      // 来源
	Desc     string                 `json:"desc"`      //简介
	Tags     []string               `json:"tags"`      // 标签列表
	Content  string                 `json:"content"`   // 信息内容
	Extras   map[string]interface{} `json:"extras"`    //扩展信息
}

func init() {
	fmt.Println("-----", IStatusDeleted)
}

// InfoStatus 信息状态
type InfoStatus struct {
	Status   IStatus `json:"status"`    // 状态 0 初始化，1 等待审核，2审核通过,3审核不通过 4取消发布，5已发布-1 删除
	IsPublic int     `json:"is_public"` // 发布后的公开状态 1 公开 0 私有
	Weight   int     `json:"weight"`    // 权重值
}

// ChkOperator 操作信息
type ChkOperator struct {
	Checker      string    `json:"cretator"`      // 审核人
	CheckContent string    `json:"check_content"` // 审核内容
	CheckResult  int       `json:"check_result"`  // 审核结果 0 不通过 1 通过
	CheckTime    time.Time `json:"check_time"`    // 审核时间
}

// PubOperator 发布操作信息
type PubOperator struct {
	Publisher   string    `json:"publisher"`    // 发布人
	PublishTime time.Time `json:"publish_time"` // 发布时间
}

// InfoAggregate 信息聚合
type InfoAggregate struct {
	ddd.BaseAggregate
	InfoID          string `json:"info_id"`
	InfoDesc        `json:"desc"`
	InfoStatus      `json:"status"`
	common.Operator `json:"operator"`
	PubOperator     `json:"pub_operator,omitempty"`
	ChkOperator     `json:"chk_operator,omitempty"`
}

// Repo 获取聚合根对应的仓储
func (i *InfoAggregate) Repo() InfoRepo {
	return i.Repository().(InfoRepo)
}
func filterDesc(info *InfoDesc) *InfoDesc {
	if info == nil {
		return nil
	}
	if len(info.Tags) > 0 {
		tmp := make([]string, 0, len(info.Tags))
		for _, v := range info.Tags {
			if v != "" {
				tmp = append(tmp, v)
			}
		}
		info.Tags = tmp
	}
	if len(info.Icon) > 0 {
		tmp := make([]string, 0, len(info.Tags))
		for _, v := range info.Tags {
			if v != "" {
				tmp = append(tmp, v)
			}
		}
		info.Tags = tmp
	}
	return info
}

// UpdateDesc 修改信息聚合中的信息描述
func (i *InfoAggregate) UpdateDesc(ctx ddd.Context, info *InfoDesc) error {
	info = filterDesc(info)
	old := *i
	err := i.Repo().UpdateDesc(ctx, i.InfoID, *info)
	if err != nil {
		return err
	}
	i.Trigger(ctx, EvtTypInfo, EvtActUpdate, &EvtUpdateDescData{
		Old:     old,
		NewDesc: info,
	})
	return err
}

// UpdateDescToInit 修改信息聚合中的信息描述 并将状态转为初始化
func (i *InfoAggregate) UpdateDescToInit(ctx ddd.Context, info *InfoDesc) error {
	info = filterDesc(info)
	old := *i
	err := i.Repo().UpdateDescToInit(ctx, i.InfoID, *info)
	if err != nil {
		return err
	}
	i.Trigger(ctx, EvtTypInfo, EvtActUpdate, &EvtUpdateDescData{
		Old:     old,
		NewDesc: info,
	})
	return err
}

// UpdateExtral 修改信息聚合中的信息描述
func (i *InfoAggregate) UpdateExtral(ctx ddd.Context, info map[string]interface{}) error {
	return i.handlerEvtActData(ctx, EvtActUpdateExtral, func() error {
		return i.Repo().UpdateExtral(ctx, i.InfoID, info)
	})
}

// Delete 删除信息聚合
func (i *InfoAggregate) Delete(ctx ddd.Context) error {

	return i.handlerEvtActData(ctx, EvtActDelete, func() error {
		return i.Repo().DeleteInfo(ctx, i.InfoID)
	})
}

// Recover 恢复删除信息聚合
func (i *InfoAggregate) Recover(ctx ddd.Context) error {

	return i.handlerEvtActData(ctx, EvtActRecover, func() error {
		return i.Repo().RecoverInfo(ctx, i.InfoID)
	})
}

// Destroy 彻底删除信息聚合
func (i *InfoAggregate) Destroy(ctx ddd.Context) error {

	err := i.Repo().DestroyInfoByID(ctx, i.InfoID)
	if err != nil {
		return err
	}
	i.Trigger(ctx, EvtTypInfo, EvtActDestroy, i.InfoDesc)
	return err
}

// CommitCheck 信息提交审核
// 状态为初始化，或审核未通过，信息可以提交审核
func (i *InfoAggregate) CommitCheck(ctx ddd.Context) error {
	if i.Status != IStatusCheckNO && i.Status != IStatusInit {
		return errors.Errorf("该信息(%v)状态(%d)不能提交审核.", i.InfoID, i.Status)
	}
	return i.handlerEvtActData(ctx, EvtActCommitCheck, func() error {
		return i.Repo().CommitCheck(ctx, i.InfoID)
	})
}

// CheckOK 信息审核通过
// 状态为 信息审核通过 由审核等待变为审核通过，
func (i *InfoAggregate) CheckOK(ctx ddd.Context, content string) error {
	if i.Status != IStatusCheckWait {
		return errors.Errorf("该信息(%v)状态(%d)不能提交审核.", i.InfoID, i.Status)
	}
	return i.handlerEvtActData(ctx, EvtActCheckOk, func() error {
		return i.Repo().CheckOK(ctx, i.InfoID, content)
	})
}

// CheckNo 信息审核不通过
// 状态为提交审核状态可以审核不通过
func (i *InfoAggregate) CheckNo(ctx ddd.Context, content string) error {
	if i.Status != IStatusCheckWait {
		return errors.Errorf("该信息(%v)状态(%d)不能提交审核.", i.InfoID, i.Status)
	}
	return i.handlerEvtActData(ctx, EvtActCheckNo, func() error {
		return i.Repo().CheckNo(ctx, i.InfoID, content)
	})
}

// Publish 信息发布
// 状态为 初始化、等待审核禁止发布或审核通过，可以转为发布，具体需要看栏目是否需要审核
func (i *InfoAggregate) Publish(ctx ddd.Context) error {
	if i.Status != IStatusCheckWait && i.Status != IStatusCheckOk && i.Status != IStatusInit && i.Status != IStatusNoPublish && i.Status != IStatusProhibitPublish {
		return errors.Errorf("该信息(%v)状态(%d)不能发布.", i.InfoID, i.Status)
	}

	return i.handlerEvtActData(ctx, EvtActPublish, func() error {
		return i.Repo().Publish(ctx, i.InfoID)
	})

}
func (i *InfoAggregate) handlerEvtActData(ctx ddd.Context, evtact string, handler func() error) error {
	edata := &EvtActData{
		Old: *i,
	}
	err := handler()
	if err != nil {
		return err
	}
	edata.New, err = i.Repo().GetInfo(ctx, i.InfoID)
	if err != nil {
		log.Warn("更新完成后获取信息失败：%v", err)
		return nil
	}
	i.Trigger(ctx, EvtTypInfo, evtact, edata)
	return err
}

// Unpublish 信息取消发布
// 状态为初始化或审核通过可以发布，具体需要看栏目是否需要审核，该检测由控制器自行实现
func (i *InfoAggregate) Unpublish(ctx ddd.Context) error {
	if i.Status != IStatusPublished {
		return errors.Errorf("该信息(%v)状态(%d)不能取消发布.", i.InfoID, i.Status)
	}
	return i.handlerEvtActData(ctx, EvtActUnpublish, func() error {
		return i.Repo().Unpublish(ctx, i.InfoID)
	})
}

// ProhibitPublish 禁止信息发布
// 状态为发布可以切换到禁止发布
func (i *InfoAggregate) ProhibitPublish(ctx ddd.Context) error {
	if i.Status != IStatusPublished && i.Status != IStatusNoPublish && i.Status != IStatusInit {
		return errors.Errorf("该信息(%v)状态(%d)不能禁止发布.", i.InfoID, i.Status)
	}
	return i.handlerEvtActData(ctx, EvtActProhibitPublish, func() error {
		return i.Repo().ProhibitPublish(ctx, i.InfoID)
	})
}

// CancelProhibitPublish 取消禁止信息发布
// 状态为禁止信息发布可以取消禁止信息发布，状态切换为取消发布状态
func (i *InfoAggregate) CancelProhibitPublish(ctx ddd.Context) error {
	if i.Status != IStatusProhibitPublish {
		return errors.Errorf("该信息(%v)状态(%d)不能取消禁止发布.", i.InfoID, i.Status)
	}
	return i.handlerEvtActData(ctx, EvtActProhibitPublish, func() error {
		return i.Repo().CancelProhibitPublish(ctx, i.InfoID)
	})
}

type infoAggregateRoot struct {
	ddd.BaseAggregateRoot
}

func (i *infoAggregateRoot) Repo() InfoRepo {
	return i.Repository().(InfoRepo)
}
func (i *infoAggregateRoot) AddInfo(ctx ddd.Context, info InfoDesc) (id string, err error) {
	ni := filterDesc(&info)
	id, err = i.Repo().AddInfo(ctx, *ni)
	if err != nil {
		return
	}
	i.Trigger(ctx, EvtTypInfo, EvtActAdd, id)
	return
}
func (i *infoAggregateRoot) GetInfo(ctx ddd.Context, id string) (ia *InfoAggregate, err error) {
	return i.Repo().GetInfo(ctx, id)
}

// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
// total 总数量
func (i *infoAggregateRoot) QueryPage(ctx ddd.Context, is InfoSearch, pi common.PageInfo) (npi common.PageResult, result []InfoAggregate, err error) {
	return i.Repo().QueryPage(ctx, is, pi)
}
func (i *infoAggregateRoot) QueryNum(ctx ddd.Context, is InfoSearch) (num int, err error) {
	return i.Repo().QueryNum(ctx, is)
}

// 根据一组信息编号获取信息列表
func (i *infoAggregateRoot) FullInfos(ctx ddd.Context, infoids []string) (result []InfoAggregate, err error) {
	return i.Repo().FullInfos(ctx, infoids)
}
